package core.proto;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JToolTip;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.ToolTipManager;

import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.TextExtractor;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.jdesktop.swingx.JXMapViewer;

import core.util.logging.UserLogWriter;
import core.util.logging.constants.Action;
import core.util.logging.constants.Location;

import app.constants.CollabVizConstants;
import static app.constants.CollabVizConstants.*;

public final class Util {

	static final DateFormat dateFormat = new SimpleDateFormat( DATE_FORMAT_NOW );
	protected static final DateFormat logDateFormat = new SimpleDateFormat( "yyyy-MM-dd HH-mm" );
	protected static Date logFileCreationTime; // Time used to create log files.   

	private static int ADJUSTED_WIDTH = WINDOW_WIDTH;
	private static int ADJUSTED_HEIGHT = WINDOW_HEIGHT;

	public static void setAdjustedHeight(int height){
		ADJUSTED_HEIGHT = height;
	}

	public static int getAdjustedWidth(){
		return ADJUSTED_WIDTH;
	}

	public static int getAdjustedHeight(){
		return ADJUSTED_HEIGHT;
	}

	static {
		logFileCreationTime = new Date(System.currentTimeMillis());
	}

	static TextExtractor createHtmlTextExtractor(File htmlFile) throws MalformedURLException, IOException{
		TextExtractor extractor = new TextExtractor(new Source(htmlFile.toURI().toURL()));
		extractor.setIncludeAttributes(false);
		extractor.setExcludeNonHTMLElements(true);
		return extractor;
	}
	
	public static InputStream getServerResourceAsStream (String resource) {
		try {
			return getServerResource(resource).openStream();
		} catch (IOException e) {
			throw new Error(e);
		}
	}
	

	public static URL getServerResource(String resource)  {
		try {
			if (resource.startsWith("/")){
				resource = resource.substring(1);
			}
			String path = InfoViz.codebase().toString() + resource;
			path = FilenameUtils.separatorsToUnix(path);
			return new URL(path);
		} catch (MalformedURLException e) {
			throw new Error("Bad url");
		}
	}

	static Object readObject(String filePath) {
		ObjectInputStream in;
		FileInputStream fin = null;
		try{
			fin = new FileInputStream(filePath);
			in = new ObjectInputStream(fin);
			return in.readObject();
		} catch (IOException ioe){
			throw new Error(ioe);
		} catch (ClassNotFoundException e) {
			throw new Error(e);
		} finally {
			if (fin != null){
				try {
					fin.close();
				} catch (IOException e) {
				}
			}
		}
	}

	static void writeObject (Object obj, String filePath){
		ObjectOutputStream out;
		FileOutputStream fout = null;
		try{
			fout = new FileOutputStream(filePath);
			out = new ObjectOutputStream(fout);
			out.writeObject(obj);
		} catch(IOException ioe){
			throw new Error(ioe);
		} finally {
			if (fout != null){
				try {
					fout.close();
				} catch (IOException e) {
				}
			}
		}
	}

	public static String removeDoubleSlash(String path){
		return path.replace("\\\\", "\\");
	}

	public static File getFile (String folder, String filename) {
		return new File(new File(folder), filename);
	}

	public static String formatDate(Date date) {
		return dateFormat.format(date);
	}

	public static String generateLogFilePath(String logFileName) {
		String date = logDateFormat.format(logFileCreationTime);
		System.out.println(date);
		return String.format("%s-%s-%s.txt", FilenameUtils.concat(LOG_FOLDER, logFileName), InfoViz.UserID, date);
	}

	/**
	 * Shortcut to print to screen. 
	 * @param obj
	 */
	public static void p(Object obj){
		System.out.println(obj);
	}

	/**
	 * Shortcut to print an error message. 
	 * @param obj
	 */
	public static void perr(Object obj){
		System.err.println(obj);
	}

	public static int getVizWidth(){
		return ADJUSTED_WIDTH - getTimelineWidth();
	}

	public static int getVizHeight(){
		return (int) (ADJUSTED_HEIGHT * VIZ_NOTES_SPLIT_RATIO);
	}

	public static int getDocWidth() {
		return (int) (ADJUSTED_WIDTH * LEFT_RIGHT_SPLIT_RATIO * (1 - FILE_TREE_SPLIT_RATIO));
	}

	public static int getDocHeight(){
		return (int) (ADJUSTED_HEIGHT * TOP_BOTTOM_SPLIT_RATIO);
	}

	public static int getFileTreeHeight(){
		return (int) (ADJUSTED_HEIGHT * TOP_BOTTOM_SPLIT_RATIO);
	}

	public static int getFileTreeWidth(){
		return (int) (ADJUSTED_WIDTH * LEFT_RIGHT_SPLIT_RATIO * FILE_TREE_SPLIT_RATIO);
	}

	public static int getTimelineHeight(){
		return ADJUSTED_HEIGHT - getDocHeight();
	}

	public static int getTimelineWidth() {
		return (int) (ADJUSTED_WIDTH * LEFT_RIGHT_SPLIT_RATIO);
	}

	public static int getMapHeight (){
		return ADJUSTED_HEIGHT - getVizHeight();
	}

	public static int getMapWidth(){
		return getVizWidth();
	}

	public static boolean lte(double left, double right){
		return Double.compare(left, right) <= 0;
	}

	public static String joinString(String delimiter, Object ...strings) {
		StringBuilder builder = new StringBuilder();

		for(int i=0; i<strings.length; ++i){
			builder.append(strings[i].toString());
			if (i + 1 != strings.length) {
				builder.append(delimiter);
			}
		}
		return builder.toString();		
	}

	public static void copyFromUrlTo(URL source, String destination) {
		File finalDestination = new File(destination);
		try {
			FileUtils.copyURLToFile(source, finalDestination);
		} catch (IOException e) {
			throw new Error(e);
		}
	}
	
	public static void unzip(String zipFilePath) {
		File zipped = new File(zipFilePath);
		if (FilenameUtils.getExtension(zipFilePath).equals("zip")){
			try {
				ZipFile zf = new ZipFile(zipped);
				@SuppressWarnings("unchecked")
				Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zf.entries();
				while (entries.hasMoreElements()){
					ZipEntry ze = entries.nextElement();
					File output = new File(FilenameUtils.concat(LOCAL_DIRECTORY, ze.getName()));
					
					if(ze.isDirectory()) {
						output.mkdir();
					} else {
						InputStream zstream = zf.getInputStream(ze);
						FileUtils.copyInputStreamToFile(zstream, output);
					}
				}
			} catch (ZipException e) {
				throw new Error(e);
			} catch (IOException e) {
				throw new Error(e);
			}
		}
	}
	
	public static void showCannotAddAnnotationPopup (JComponent parent) {
		JOptionPane.showMessageDialog(parent, "hello");
	}

}